package yagwl.server.demo;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import yagwl.client.model.ItemDTO;
import yagwl.client.model.TreeNodeDTO;
import yagwl.client.model.demo.CatalogRpcService;
import yagwl.client.model.fnd.RpcStatus;
import yagwl.service.demo.CommerceService;
import yagwl.service.demo.CommerceServiceImpl;
import yagwl.service.demo.ProductCategoryEntity;
import yagwl.service.demo.ProductEntity;
import yagwl.service.util.svc.BaseException;
import yagwl.service.util.svc.Context;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

@SuppressWarnings("serial")
public class CatalogRpcServiceImpl extends RemoteServiceServlet implements
    CatalogRpcService {

  private static final Logger log = Logger
      .getLogger(CatalogRpcServiceImpl.class.getName());
  private CommerceService svc = CommerceServiceImpl.getInstance();

  @Override
  public TreeNodeDTO getCategoryTree() {
    ProductCategoryEntity rootEntity = svc.getCategoryTree();
    TreeNodeDTO rootDTO = copyProductCategory(rootEntity);
    copyChildrenRecursive(rootEntity, rootDTO);
    return rootDTO;
  }

  private void copyChildrenRecursive(ProductCategoryEntity catEntity,
      TreeNodeDTO catDTO) {
    if (catEntity.getChildren() == null)
      return;
    for (ProductCategoryEntity childEntity : catEntity.getChildren()) {
      TreeNodeDTO childDTO = copyProductCategory(childEntity);
      catDTO.addChild(childDTO);
      childDTO.setParent(catDTO);
      if (childEntity.getChildren() != null) // this check is not really necessary
        copyChildrenRecursive(childEntity, childDTO);
    }
  }

  @Override
  public RpcStatus createCategory(TreeNodeDTO catDTO) {
    if (!authorized())
      return new RpcStatus();
    ProductCategoryEntity cat;
    RpcStatus stat = new RpcStatus();
    try {
      cat = svc.createCategory(copyProductCategory(catDTO));
    } catch (BaseException e) {
      stat.setErrorCode(e.getErrorCode().toString());
      stat.setMessage(e.getMessage());
      return stat;
    }
    stat.setObjectId(cat.getEncryptedProductCategoryId());
    return stat;
  }

  private boolean authorized() {
    Context ctx = Context.getCurrentInstance();
    return Boolean.parseBoolean(ctx.getAttributeStr("AuthorizeTransactions"));
  }

  @Override
  public RpcStatus updateCategory(TreeNodeDTO catDTO) {
    if (!authorized())
      return new RpcStatus();
    RpcStatus stat = new RpcStatus();
    try {
      svc.updateCategory(copyProductCategory(catDTO));
    } catch (BaseException e) {
      stat.setErrorCode(e.getErrorCode().toString());
      stat.setMessage(e.getMessage());
      return stat;
    }
    return stat;
  }

  @Override
  public RpcStatus deleteCategorySubTree(String catogoryId) {
    if (!authorized())
      return new RpcStatus();
    RpcStatus stat = new RpcStatus();
    try {
      svc.deleteCategorySubTree(catogoryId);
    } catch (BaseException e) {
      stat.setErrorCode(e.getErrorCode().toString());
      stat.setMessage(e.getMessage());
      return stat;
    }
    return stat;
  }

  @Override
  public RpcStatus addProduct(String categoryId, String productId) {
    if (!authorized())
      return new RpcStatus();
    RpcStatus stat = new RpcStatus();
    try {
      svc.addProduct(categoryId, productId);
    } catch (BaseException e) {
      stat.setErrorCode(e.getErrorCode().toString());
      stat.setMessage(e.getMessage());
      return stat;
    }
    return stat;
  }

  @Override
  public RpcStatus removeProduct(String catogoryId, String productId) {
    if (!authorized())
      return new RpcStatus();
    RpcStatus stat = new RpcStatus();
    try {
      svc.removeProduct(catogoryId, productId);
    } catch (BaseException e) {
      stat.setErrorCode(e.getErrorCode().toString());
      stat.setMessage(e.getMessage());
      return stat;
    }
    return stat;
  }

  @Override
  public List<ItemDTO> getProducts() {
    List<ItemDTO> listDTO = new ArrayList<ItemDTO>();
    List<ProductEntity> list = svc.getProducts();
    for (ProductEntity prd : list) {
      ItemDTO prdDTO = copyProduct(prd);
      listDTO.add(prdDTO);
    }
    return listDTO;
  }

  @Override
  public RpcStatus createProduct(ItemDTO prdDTO) {
    if (!authorized())
      return new RpcStatus();
    ProductEntity prd;
    RpcStatus stat = new RpcStatus();
    try {
      prd = svc.createProduct(copyProduct(prdDTO));
    } catch (BaseException e) {
      stat.setErrorCode(e.getErrorCode().toString());
      stat.setMessage(e.getMessage());
      return stat;
    }
    stat.setObjectId(prd.getEncryptedProductId());
    return stat;
  }

  @Override
  public RpcStatus updateProduct(ItemDTO prdDTO) {
    if (!authorized())
      return new RpcStatus();
    RpcStatus stat = new RpcStatus();
    try {
      svc.updateProduct(copyProduct(prdDTO));
    } catch (BaseException e) {
      stat.setErrorCode(e.getErrorCode().toString());
      stat.setMessage(e.getMessage());
      return stat;
    }
    return stat;
  }

  @Override
  public RpcStatus deleteProduct(String productId) {
    if (!authorized())
      return new RpcStatus();
    RpcStatus stat = new RpcStatus();
    try {
      svc.deleteProduct(productId);
    } catch (BaseException e) {
      stat.setErrorCode(e.getErrorCode().toString());
      stat.setMessage(e.getMessage());
      return stat;
    }
    return stat;
  }

  public TreeNodeDTO copyProductCategory(ProductCategoryEntity cat) {
    TreeNodeDTO catDTO = new TreeNodeDTO();
    catDTO.setId(cat.getEncryptedProductCategoryId());
    catDTO.setLabel(cat.getName());
    catDTO.put("name", cat.getName());
    catDTO.put("imageUrl", cat.getImageUrl());

    if (cat.getProducts() == null)
      return catDTO;
    for (ProductEntity prd : cat.getProducts()) {
      if (catDTO.getItems() == null)
        catDTO.setItems(new ArrayList<ItemDTO>());
      catDTO.getItems().add(copyProduct(prd));
    }

    return catDTO;
  }

  private ProductCategoryEntity copyProductCategory(TreeNodeDTO catDTO) {
    ProductCategoryEntity cat = new ProductCategoryEntity();
    if (catDTO.getId() != null)
      cat.setEncryptedProductCategoryId(catDTO.getId());
    if (catDTO.getParent() != null)
      cat.setEncryptedParentProductCategoryId(catDTO.getParent().getId());
    cat.setName((String) catDTO.get("name"));
    cat.setImageUrl((String) catDTO.get("imageUrl"));
    return cat;
  }

  private ItemDTO copyProduct(ProductEntity prd) {
    ItemDTO prdDTO = new ItemDTO();
    prdDTO.setId(prd.getEncryptedProductId());
    prdDTO.setLabel(prd.getName());
    prdDTO.put("name", prd.getName());
    prdDTO.put("description", prd.getDescription());
    prdDTO.put("imageUrl", prd.getImageUrl());
    prdDTO.put("priceStr", prd.getPriceStr());
    prdDTO.put("priceWithCurrency", prd.getPriceWithCurrency());
    prdDTO.put("field1", prd.getField1());
    prdDTO.put("field2", prd.getField2());
    prdDTO.put("field3", prd.getField3());
    prdDTO.put("field4", prd.getField4());
    prdDTO.put("field5", prd.getField5());
    prdDTO.put("field6", prd.getField6());
    log.fine(prdDTO.getId());
    return prdDTO;
  }

  // TODO P3 automate copy
  private ProductEntity copyProduct(ItemDTO prdDTO) {
    ProductEntity prd = new ProductEntity();
    if (prdDTO.getId() != null)
      prd.setEncryptedProductId(prdDTO.getId());
    prd.setName(prdDTO.get("name"));
    prd.setDescription(prdDTO.get("description"));
    prd.setImageUrl(prdDTO.get("imageUrl"));
    prd.setPriceStr(prdDTO.get("priceStr"));
    prd.setField1(prdDTO.get("field1"));
    prd.setField2(prdDTO.get("field2"));
    prd.setField3(prdDTO.get("field3"));
    prd.setField4(prdDTO.get("field4"));
    prd.setField5(prdDTO.get("field5"));
    prd.setField6(prdDTO.get("field6"));
    return prd;
  }

}
